package com.junpuxin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.junpuxin.dto.*;
import com.junpuxin.entity.Club;
import com.junpuxin.excel.ClubExcel;
import com.junpuxin.exception.IllegalParamException;
import com.junpuxin.exception.ServerErrorException;
import com.junpuxin.exception.VersionException;
import com.junpuxin.mapper.ClubMapper;
import com.junpuxin.service.ClubService;
import com.junpuxin.vo.ClubVO;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author junpuxin
 */
@Service
@CacheConfig(cacheNames = "club")
public class ClubServiceImpl implements ClubService {

    @Resource
    private ClubMapper clubMapper;

    @CacheEvict(allEntries = true)
    @Override
    public int insert(ClubInsertDTO dto) {
        String info = dto.getInfo();
        List<String> tag = dto.getTag();
        // 拷贝属性
        Club club = BeanUtil.copyProperties(dto, Club.class);

        // 判断开班时间和预计结班时间
        if (dto.getStartTime().isAfter(dto.getExpectedEndTime())) {
            throw new IllegalParamException("开班时间不能晚于预计结班时间");
        }

        // 设置默认值
        club.setInfo(StrUtil.isBlank(info) ? "暂无描述" : info);
        club.setTag(CollUtil.isEmpty(tag) ? "暂无标签" : String.join(", ", dto.getTag()));
        club.setVersion(0L);
        club.setDeleted(0);
        club.setCreated(LocalDateTime.now());
        club.setUpdated(LocalDateTime.now());
        // DB添加
        int result = clubMapper.insert(club);
        if (result < 0) {
            throw new ServerErrorException("DB添加失败");
        }
        return result;
    }

    @Cacheable(key = "#p0", condition = "#p0 != null", unless = "#result == null")
    @Override
    public Club select(Long id) {
        // DB查询
        Club result = clubMapper.select(id);
        if(ObjectUtil.isNull(result)) {
            throw new ServerErrorException("记录不存在");
        }
        return result;
    }

    @Cacheable(key = "#root.methodName", unless = "#result == null")
    @Override
    public List<ClubVO> list() {
        return clubMapper.list(new ClubPageDTO())
                .stream()
                .map(club -> BeanUtil.copyProperties(club, ClubVO.class))
                .collect(Collectors.toList());
    }

    @Cacheable(key = "#root.methodName + ':' + #p0.toString()",
                condition = "#p0 != null",
                unless = "#result == null")
    @Override
    public PageInfo<Club> page(ClubPageDTO dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        return new PageInfo<>(clubMapper.list(dto));
    }

    @CacheEvict(allEntries = true)
    @Transactional
    @Retryable(retryFor = VersionException.class)
    @Override
    public int update(ClubUpdateDTO dto) {
        Long id = dto.getId();
        if(ObjectUtil.isNull(id)) {
            throw new IllegalParamException("ID为空");
        }
        Club club = clubMapper.select(id);
        if(ObjectUtil.isNull(club)) {
            throw new ServerErrorException("记录不存在");
        }
        BeanUtil.copyProperties(dto, club);
        // 判断开班时间和预计结班时间
        if (dto.getStartTime().isAfter(dto.getExpectedEndTime())) {
            throw new IllegalParamException("开班时间不能晚于预计结班时间");
        }
        club.setTag(CollUtil.isEmpty(dto.getTag()) ? "暂无标签" : String.join(", ", dto.getTag()));
        // 设置默认值
        club.setUpdated(LocalDateTime.now());
        // DB修改
        int result = clubMapper.update(club);
        if (result <= 0) {
            throw new VersionException("DB修改失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int delete(Long id) {
        int result = clubMapper.delete(id);
        if (result <= 0) {
            throw new ServerErrorException("DB删除失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int deleteBatch(List<Long> ids) {
        int result = clubMapper.deleteBatch(ids);
        if (result <= 0) {
            throw new ServerErrorException("DB批量删除失败");
        }
        return result;
    }

    @Override
    public List<ClubExcel> getExcelData() {
        return clubMapper.list(new ClubPageDTO())
                .stream()
                .map(club -> {
                    ClubExcel clubExcel = BeanUtil.copyProperties(club, ClubExcel.class);
                    if (ObjectUtil.isNotNull(club.getDirection())) {
                        clubExcel.setDirectionTitle(club.getDirection().getTitle());
                    }
                    return clubExcel;
                })
                .collect(Collectors.toList());
    }

    @CacheEvict(allEntries = true)
    @Override
    public int endClub(Long id) {
        // 查询班级记录
        Club club = clubMapper.select(id);
        if (ObjectUtil.isNull(club)) {
            throw new ServerErrorException("班级记录不存在");
        }
        // 判断是否已结班
        if (ObjectUtil.isNotNull(club.getEndTime())) {
            throw new IllegalParamException("班级已结班");
        }
        // DB修改：修改班级记录
        club.setEndTime(LocalDateTime.now());
        int result = clubMapper.update(club);
        if (result < 0) {
            throw new IllegalParamException("DB班级记录修改失败");
        }
        return result;
    }
}
